//
//  dg_frame.c
//  实现迪文显示屏的串口协议基础架构
//
//  Created by Eywen on 2021/2/3.
//

#include "dg_frame.h"
#include <string.h>
#include <stdarg.h>

static frame_list_t g_frame_list; /* 保存待处理的数据帧 */

static frame_status_t check_frame_integrity(uint8_t *frame_data, uint16_t frame_len);
static uint8_t get_uint8(uint8_t *ptr);
static uint16_t get_uint16(uint8_t *ptr);
static uint32_t get_uint32(uint8_t *ptr);
static uint64_t get_uint64(uint8_t *ptr);
static float get_float(uint8_t *ptr);
static void set_uint8(uint8_t *ptr, uint8_t var);
static void set_uint16(uint8_t *ptr, uint16_t var);
static void set_uint32(uint8_t *ptr, uint32_t var);
static void set_uint64(uint8_t *ptr, uint64_t var);
static void set_float(uint8_t *ptr, float var);
static void set_double(uint8_t *ptr, double var);
static void frame_list_read_index_up(frame_list_t *frame_list);
static void frame_list_write_index_up(frame_list_t *frame_list);
static void frame_list_count_up(frame_list_t *frame_list);
static void frame_list_count_down(frame_list_t *frame_list);
static bool frame_list_is_empty(frame_list_t *frame_list);
static bool frame_list_is_full(frame_list_t *frame_list);
static void frame_list_pop(frame_list_t *frame_list, frame_t *frame);
static bool frmae_list_append(frame_list_t *frame_list, uint8_t *frame_std_buf,
        uint16_t buf_len);

#if (defined DG_FRAME_CHECK_CRC16) || (defined DG_FRAME_CHECK_SUM) 
static uint16_t cal_check_code(uint8_t *data, uint16_t len);
#endif


/* 处理帧缓冲数组的数据帧 */
bool handle_frame_buff(handle_t *frame_handle_list, uint16_t list_len)
{
    frame_t frame;
    frame_list_t *frame_list;
    frame_list = &g_frame_list;
    /* 帧缓存中不为空 */
    while(frame_list_is_empty(frame_list) == false){
        frame_list_pop(frame_list, &frame);
		//debug_dg_hex_p(frame.buff, 6);
        /* 处理帧 */
        for (uint16_t i = 0; i < list_len; i++){
			uint8_t funcode = get_frame_fun_code(&frame);
            if (frame_handle_list[i].fun_code == funcode){
                if(frame_handle_list[i].handle_fun){
                    frame_handle_list[i].handle_fun(&frame);
                    break;
                }
            }
        }
    }
    return true;
}

/* 将接收到的数据提取出来并存储到内存 */
frame_status_t deframe(uint8_t *frame_data, uint16_t frame_len)
{
    uint16_t i;
    uint16_t data_len, one_frame_len;
    uint16_t head_pos;
    frame_status_t flag_frame;

    if (frame_len < DG_FRAME_MIN_LEN){
        return error_integrity;
    }

    //debug_hex(frame_data, frame_len);

    flag_frame = error_integrity;
    /* 查找帧头和帧尾 */
    for (i = 0; i <= (frame_len - DG_FRAME_MIN_LEN); i++){
        /* 匹配帧头的位置 */
        head_pos = i;
		uint16_t head = get_uint16(frame_data + head_pos);
        if (head != DG_FRAME_HEAD){
			debug_error("error frame head: %u %x %x", i, head, DG_FRAME_HEAD);
            continue;
        }

        data_len = get_uint8(frame_data + i + DG_FRAME_DATA_LEN_OFFSET);
        one_frame_len = data_len + DG_FRAME_MIN_LEN;
		if((i + one_frame_len) > frame_len){
			return flag_frame;
		}

        /* 帧长度不对,继续查找帧头 */
        if (one_frame_len > frame_len){
			debug_error("error frame len, %d %d", DG_FRAME_MIN_LEN, data_len);
            continue;
        }

        /* 帧校验检测 */
        if (check_frame_integrity(frame_data + i, one_frame_len) != ok_integrity){
			debug_error("error frame check");
            continue;
        }
        frmae_list_append(&g_frame_list, frame_data + i, one_frame_len);
        flag_frame = ok_integrity;
        i += (one_frame_len - 1);
    }

    return flag_frame;
}

frame_status_t check_frame_integrity(uint8_t *frame_data, uint16_t frame_len)
{
    uint16_t data_len;
    
    /* 判断帧头是否正确 */
    if (get_uint16(frame_data) != DG_FRAME_HEAD){
        debug_dg_frame_p("frame error head");
        return error_head;
    }

    data_len = get_uint8(frame_data + DG_FRAME_DATA_LEN_OFFSET);
    /* 长度错误 */
    if ((data_len + DG_FRAME_MIN_LEN) > frame_len){
        debug_dg_frame_p("frame error len");
        return error_len;
    }
#if (defined DG_FRAME_CHECK_CRC16) || (defined DG_FRAME_CHECK_SUM) 
    uint16_t check_code, check_val;
    /* 计算校验数据是否损坏 */
    check_val = cal_check_code(frame_data + 
        DG_FRAME_CHECK_FIELD_BEGIN, DG_FRAME_CHECK_FIELD_MIN_LEN + data_len);
    check_code = get_uint16(frame_data + 
        DG_FRAME_CHECK_CODE_MIN_OFFSET + data_len);
    if (check_code != check_val){
        debug_dg_frame_p("frame check error: %u != %u", check_val, check_code);
        return error_check;
    }
#endif
    return ok_integrity;
}

void frame_list_init(frame_list_t *frame_list)
{
    frame_list->read_index = 0;
    frame_list->write_index = 0;
    frame_list->count = 0;
}

bool frame_list_is_full(frame_list_t *frame_list)
{
    return frame_list->count == DG_FRAME_BUF_LIST_MAX_LEN ? true : false;
}

bool frame_list_is_empty(frame_list_t *frame_list)
{
    return frame_list->count == 0 ? true : false;
}

void frame_list_read_index_up(frame_list_t *frame_list)
{
    frame_list->read_index++;
    frame_list->read_index %= DG_FRAME_BUF_LIST_MAX_LEN;
}

void frame_list_write_index_up(frame_list_t *frame_list)
{
    frame_list->write_index++;
    frame_list->write_index %= DG_FRAME_BUF_LIST_MAX_LEN;
}

void frame_list_count_up(frame_list_t *frame_list)
{
    frame_list->count++;
}

void frame_list_count_down(frame_list_t *frame_list)
{
    if (frame_list->count)
    {
        frame_list->count--;
    }
}

void frame_list_pop(frame_list_t *frame_list, frame_t *frame)
{
    if (frame_list_is_empty(frame_list) == true){
        return;
    }

    if (frame != NULL){
        memcpy(frame, frame_list->frame + frame_list->read_index, sizeof(frame_t));
    }
    frame_list_read_index_up(frame_list);
    frame_list_count_down(frame_list);
}

bool frmae_list_append(frame_list_t *frame_list, uint8_t *frame_std_buf, uint16_t buf_len)
{
    frame_t *ptr;

    /* 缓存满了，直接丢弃这个包 */
    if (frame_list_is_full(frame_list) == true){
        debug_dg_warning_p("list is full");
        return false;
    }

    ptr = frame_list->frame + frame_list->write_index;
    memcpy(ptr, frame_std_buf, buf_len);

    /* 数据域读取索引 */
    ptr->buff_read_index = 0;

    /* 更新帧缓存函数索引 */
    frame_list_write_index_up(frame_list);
    frame_list_count_up(frame_list);

    return true;
}

#if (defined DG_FRAME_CHECK_CRC16)
uint16_t cal_check_code(uint8_t *data, uint16_t len)
{
    return 0;
}
#endif

uint8_t frame_pull_uint8(frame_t *frame)
{
    uint8_t ret;
    if (frame->buff_read_index >= get_frame_data_len(frame)){
        debug_dg_error_p("error read index over");
        return 0;
    }
    ret = get_uint8(frame->buff + DG_FRAME_DATA_OFFSET + frame->buff_read_index);
    frame->buff_read_index += sizeof(uint8_t);
    return ret;
}

uint16_t frame_pull_uint16(frame_t *frame)
{
    uint16_t ret;
    ret = get_uint16(frame->buff + DG_FRAME_DATA_OFFSET + frame->buff_read_index);
    frame->buff_read_index += sizeof(uint16_t);
    return ret;
}

uint32_t frame_pull_uint32(frame_t *frame)
{
    uint32_t ret;
    ret = get_uint32(frame->buff + DG_FRAME_DATA_OFFSET + frame->buff_read_index);
    frame->buff_read_index += sizeof(uint32_t);
    return ret;
}

uint64_t frame_pull_uint64(frame_t *frame)
{
    uint64_t ret;
    ret = get_uint64(frame->buff + DG_FRAME_DATA_OFFSET + frame->buff_read_index);
    frame->buff_read_index += sizeof(uint64_t);
    return ret;
}

float frame_pull_flaot(frame_t *frame)
{
    float ret;
    ret = get_float(frame->buff + DG_FRAME_DATA_OFFSET + frame->buff_read_index);
    frame->buff_read_index += sizeof(float);
    return ret;
}

uint16_t frame_pull_string(frame_t *frame, uint8_t *buff, uint16_t buff_len)
{
    uint16_t i;
    for (i = 0; i < buff_len; i++){
        *(buff + i) = frame_pull_uint8(frame);
        if (*(buff + i) == 0){
            break;
        }
    }
    return i;
}

uint16_t frame_pull_bytes(frame_t *frame, uint8_t *buf, uint16_t buff_len)
{
    uint16_t i;
    for (i = 0; i < buff_len; i++){
        *(buf + i) = frame_pull_uint8(frame);
        if (frame->buff_read_index >= get_frame_data_len(frame)){
            return ++i;
        }
    }
    return i;
}

void frame_push_uint8(frame_t *frame, uint8_t var)
{
    set_uint8(frame->buff + DG_FRAME_DATA_OFFSET + frame->buff_write_index, var);
    frame->buff_write_index += sizeof(var);
}

void frame_push_uint16(frame_t *frame, uint16_t var)
{
    set_uint16(frame->buff + DG_FRAME_DATA_OFFSET + frame->buff_write_index, var);
    frame->buff_write_index += sizeof(var);
}

void frame_push_uint32(frame_t *frame, uint32_t var)
{
    set_uint32(frame->buff + DG_FRAME_DATA_OFFSET + frame->buff_write_index, var);
    frame->buff_write_index += sizeof(var);
}

void frame_push_uint64(frame_t *frame, uint64_t var)
{
    set_uint64(frame->buff + DG_FRAME_DATA_OFFSET + frame->buff_write_index, var);
    frame->buff_write_index += sizeof(var);
}

void frame_push_float(frame_t *frame, float var)
{
    set_float(frame->buff + DG_FRAME_DATA_OFFSET + frame->buff_write_index, var);
    frame->buff_write_index += sizeof(var);
}

void frame_push_double(frame_t *frame, double var)
{
    set_double(frame->buff + DG_FRAME_DATA_OFFSET + frame->buff_write_index, var);
    frame->buff_write_index += sizeof(var);
}

void frame_push_bytes(frame_t *frame, uint8_t *bytes, uint16_t len)
{
    for(uint16_t i = 0 ;i < len; i++){
        if(frame->buff_write_index < DG_FRAME_MAX_DATA_LEN){
            frame_push_uint8(frame, *(bytes + i));
        }
        else{
            break;
        }
    }
}

/* \0 也需要添加进去*/
void frame_push_string(frame_t *frame, char * str)
{
    int len;
    //len = strlen(str) + 1; /* 添加\0 */
    len = strlen(str) + 0; /* 不添加\0 */
    frame_push_bytes(frame, (uint8_t *)str, (uint16_t)len);
}

/* 帧结构初始化 */
void frame_init(frame_t *frame, uint8_t fun_code)
{
    /* 设置帧头 */
    set_frame_head(frame, DG_FRAME_HEAD);
    /* 设置功能码 */
    set_frame_fun_code(frame, fun_code);
    /* 写数据域指针归位 */
    frame->buff_write_index = 0;
}

/* repy_frame: 即将回复的帧
   recv_frame： 接收到的帧*/
void frame_repy_init(frame_t *repy_frame, frame_t *recv_frame)
{
    /* 设置帧头 */
    set_frame_head(repy_frame, DG_FRAME_HEAD);
    /* 设置功能码 */
    set_frame_fun_code(repy_frame, get_frame_fun_code(recv_frame));

    repy_frame->buff_write_index = 0;
}

void set_frame_fun_code(frame_t *frame, uint8_t fun_code)
{
    set_uint8(frame->buff + DG_FRAME_FUN_CODE_OFFSET, fun_code);
}
void set_frame_data_len_field(frame_t *frame, uint8_t date_len)
{
    set_uint8(frame->buff + DG_FRAME_DATA_LEN_OFFSET, date_len);
}
void set_frame_head(frame_t *frame, uint16_t head)
{
    set_uint16(frame->buff + DG_FRAME_HEAD_OFFSET, head);
}

uint8_t *frame_repy_create(frame_t *frame)
{
    /* 设置数据长度 */
    set_frame_data_len_field(frame, frame->buff_write_index + DG_FRAME_DATA_LEN_MIN);
    
#if (defined DG_FRAME_CHECK_CRC16) || (defined DG_FRAME_CHECK_SUM) 
    uint16_t check_code;    
    /* 计算校验值 */
    check_code = cal_check_code(frame->buff + DG_FRAME_CHECK_FIELD_BEGIN,
                                frame->buff_write_index + DG_FRAME_MIN_CHEK_LEN);
    /* 填入校验码*/
    frame_push_uint16(frame, check_code);
#endif
    return frame->buff;
}

uint16_t get_frame_write_idx_len(frame_t *frame)
{
    return frame->buff_write_index;
}

uint8_t get_frame_fun_code(frame_t *frame)
{
    return get_uint8(frame->buff + DG_FRAME_FUN_CODE_OFFSET);
}

/* 获取帧数据长度（指令+数据+校验字节数） */
uint8_t get_frame_data_len_feild(frame_t *frame)
{
    return get_uint8(frame->buff + DG_FRAME_DATA_LEN_OFFSET);
}


/* 帧内数据的个数的长度，不包括指令和校验 */
uint8_t get_frame_data_len(frame_t *frame)
{
    return get_uint8(frame->buff + DG_FRAME_DATA_LEN_OFFSET) 
            - DG_FRAME_DATA_LEN_MIN;
}


/* 整个帧的长度 */
uint8_t get_frame_len(frame_t *frame)
{
    //包括帧头长度
    return get_uint8(frame->buff + DG_FRAME_DATA_LEN_OFFSET) + 3;
}

static inline uint8_t get_uint8(uint8_t *ptr)
{
    return *ptr;
}

static inline uint16_t get_uint16(uint8_t *ptr)
{
#if DG_FRAME_ENDIAN == DG_FRAME_LITTLE_ENDIAN
    return ((uint16_t)get_uint8(ptr) << 8) | (get_uint8(ptr + 1));
#else
    return ((uint16_t)get_uint8(ptr + 1) << 8) | (get_uint8(ptr));
#endif
}

static inline uint32_t get_uint32(uint8_t *ptr)
{
#if DG_FRAME_ENDIAN == DG_FRAME_LITTLE_ENDIAN
    return ((uint32_t)get_uint8(ptr + 0)) << 24 | (uint32_t)(get_uint8(ptr + 1)) << 16 | \
            (uint32_t)(get_uint8(ptr + 2) << 8) | (uint32_t)(get_uint8(ptr + 3));
#else
    return ((uint32_t)get_uint8(ptr) << 3) | (uint32_t)(get_uint8(ptr + 2)) << 8 | \
            (uint32_t)(get_uint8(ptr + 1)) << 16 | (uint32_t)(get_uint8(ptr + 0)) << 24;
#endif
}

static inline uint64_t get_uint64(uint8_t *ptr)
{
#if DG_FRAME_ENDIAN == DG_FRAME_LITTLE_ENDIAN
    return ((uint64_t)get_uint8(ptr + 0)) << 56 | (uint64_t)(get_uint8(ptr + 1)) << 48 | \
            (uint64_t)(get_uint8(ptr + 2)) << 40 | (uint64_t)(get_uint8(ptr + 3)) << 32 | \
            (uint64_t)(get_uint8(ptr + 4)) << 24 | (uint64_t)(get_uint8(ptr + 5)) << 16 | \
            (uint64_t)(get_uint8(ptr + 6)) << 8 | (uint64_t)(get_uint8(ptr + 7)) << 0;
#else
    return ((uint64_t)get_uint8(ptr + 7)) << 0 | (uint64_t)(get_uint8(ptr + 6)) << 8 | \
            (uint64_t)(get_uint8(ptr + 5)) << 16 | (uint64_t)(get_uint8(ptr + 4)) << 24 | \
            (uint64_t)(get_uint8(ptr + 3)) << 32 | (uint64_t)(get_uint8(ptr + 2)) << 40 | \
            (uint64_t)(get_uint8(ptr + 1)) << 48 | (uint64_t)(get_uint8(ptr + 0)) << 56;
#endif
}

static float get_float(uint8_t *ptr)
{
    uint32_t tmp;
    tmp = get_uint32(ptr);
    return *(float *)(&tmp);
}

static void inline set_uint8(uint8_t *ptr, uint8_t var)
{
    *ptr = var;
}

static void set_uint16(uint8_t *ptr, uint16_t var)
{
    uint32_t i, offset;

#if DG_FRAME_ENDIAN == DG_FRAME_LITTLE_ENDIAN
    for (i = 0, offset = 8 * (sizeof(var) - 1); i < sizeof(var);
         i++, offset -= 8){
        set_uint8(ptr + i, (var >> offset) & 0xff);
    }
#else
    for (i = (sizeof(var) - 1), offset = 8 * (sizeof(var) - 1); i >= 0;
         i--, offset -= 8){
        set_uint8(ptr + i, (var >> offset) & 0xff);
    }
#endif
}

static void set_uint32(uint8_t *ptr, uint32_t var)
{
    int i, offset;

#if DG_FRAME_ENDIAN == DG_FRAME_LITTLE_ENDIAN
    for (i = 0, offset = 8 * (sizeof(var) - 1); i < sizeof(var);
         i++, offset -= 8){
        set_uint8(ptr + i, (var >> offset) & 0xff);
    }
#else
    for (i = (sizeof(var) - 1), offset = 8 * (sizeof(var) - 1); i >= 0;
         i--, offset -= 8){
        set_uint8(ptr + i, (var >> offset) & 0xff);
    }
#endif
}

static void set_uint64(uint8_t *ptr, uint64_t var)
{
    int i, offset;

#if DG_FRAME_ENDIAN == DG_FRAME_LITTLE_ENDIAN
    for (i = 0, offset = 8 * (sizeof(var) - 1); i < sizeof(var);
         i++, offset -= 8){
        set_uint8(ptr + i, (var >> offset) & 0xff);
    }
#else
    for (i = (sizeof(var) - 1), offset = 8 * (sizeof(var) - 1); i >= 0;
         i--, offset -= 8){
        set_uint8(ptr + i, (var >> offset) & 0xff);
    }
#endif
}

static void set_float(uint8_t *ptr, float var)
{
    set_uint32(ptr, *(uint32_t *)&var);
}

static void set_double(uint8_t *ptr, double var)
{
    set_uint64(ptr, *(uint64_t *)&var);
}

/* 
功能： 设置帧功能码、数据域（支持多参数传入）
frame: 帧指针
funcode： 帧功能
data_num： 数据个数

使用举例：
frame_set(frame_ptr, 0x80, 4,   //3表示后面放4个数据点
    data_type_uint8, 0xf1,      //第一个数据点是一个uint8_t类型的
    data_type_float, 3.14,      //第二个数据点是一个float类型的
    data_type_bytes, sizeof(bytes_arr), bytes_arr,  //第三个是字节数组类型
    data_type_string, "hello");   //第四个是字符串类型
注意， 对于uint64类型的数字，必须使用强制(uint64_t)num作为参数传进去，否则编译器
可能优化成int类型到内存引起bug,如果是变量则无所谓。如(uint64_t)3,不加强制时3会被
编译器优化成int到内存。
*/
void frame_set(frame_t *frame,uint8_t funcode, int data_num, ...)
{
    va_list v1;
    frame_data_type_t type;
    frame_init(frame, funcode);
    
    va_start(v1, data_num);	
    for(int i = 0; i < data_num; i++){
        /* 根据传进来的参数类型确定下一个参数类型，注意一些char、
            uchar的会自动转换为int, float会转换成double */
        type = (frame_data_type_t)va_arg(v1, int);	
        switch(type){
            case data_type_int8:
            case data_type_uint8:
                do{
                    uint8_t data;
                    data = va_arg(v1, uint32_t);
                    frame_push_uint8(frame, data);
                }while(0);break;
            case data_type_int16:
            case data_type_uint16:
                do{
                    uint16_t data;
                    data = va_arg(v1, uint32_t);
                    frame_push_uint16(frame, data);
                }while(0);break;
            case data_type_int32:
            case data_type_uint32:
                do{
                    uint32_t data;
                    data = va_arg(v1, uint32_t);
                    frame_push_uint32(frame, data);
                }while(0);break;
            case data_type_int64:
            case data_type_uint64:
                do{
                    uint64_t data;
                    data = va_arg(v1, uint64_t);
                    frame_push_uint64(frame, data);
                }while(0);break;
            case data_type_float:
                do{
                    float data;
                    data = va_arg(v1, double);
                    frame_push_float(frame, data);
                }while(0);break;
            case data_type_double:
                do{
                    double data;
                    data = va_arg(v1, double);
                    frame_push_double(frame, data);
                }while(0);break;
            case data_type_bytes:
                do{
                    uint8_t *ptr;
                    int bytes_cnt;
                    bytes_cnt = (int)va_arg(v1, int);
                    ptr = (uint8_t *)va_arg(v1, int);
                    frame_push_bytes(frame, ptr, bytes_cnt);
                }while(0); break;
            case data_type_string:
                do{
                    char *ptr;
                    ptr = (char *)va_arg(v1, int);
                    frame_push_string(frame, ptr);
                }while(0); break;
            default: //错误
                debug_dg_warning_p("error frame_data_type_t\r\n");
                break;
        }
    }
    va_end(v1);
    /* 组装好帧校验和长度 */
    frame_repy_create(frame);
}

